- Senior Software Engineer
- CDI co-spec lead, Java EE 8 EG
- Red Hat, Inc.
- @antoine_sd
- www.next-presso.com
- github.com/antoinesd
| Slides available at rafabene.github.io/deltaspike-cdi-toolbox/ |
| OCP (Open Closed Principle) in CDI |
| To integrate 3rd party libraries, frameworks or legacy components |
| To change existing configuration or behavior |
| To extend CDI and Java EE |
| Thanks to them, Java EE can evolve between major releases |
| Implement javax.enterprise.inject.spi.Extension |
| Register the Extension |
| Observe SPI events at boot time related to the bean manager lifecycle |
Service provider of the service javax.enterprise.inject.spi.Extension declared in META-INF/services |
| Just put the fully qualified name of your extension class in this file |
import javax.enterprise.event.Observes;
import javax.enterprise.inject.spi.Extension;
public class CdiExtension implements Extension {
void beforeBeanDiscovery(@Observes BeforeBeanDiscovery bbd) {
}
//...
void afterDeploymentValidation(@Observes AfterDeploymentValidation adv) {
}
} @Inject @Property("key1")
private String property1;
@Inject @Property("key2")
private String property2;| It can be achieved by @Produces but it could lead to: Unsatisfied dependencies for type String with qualifiers @Property… |
@Produces
@Property("key1")
public String propriedade1Producer()
{
return propertiesFile.getProperty("key1");
}| One of the most powerful feature of the CDI specification |
| Not really popularized, partly due to: |
| CDI is a specification. It doesn’t provide business features |
| but it includes a powerful hook to add these business features |
| The "Poortable extensions" feature is this hook |
| Thanks to it, CDI can be easily enhanced with new high level features |
| A collection of ready to use extensions to help you in your projects |
| A toolbox to help you develop new CDI portable extensions |
| A great way to learn how to develop your own extension by browsing the source code |
| The most obvious entry point to CDI eco-system |
TODO Move content to here
TODO Move content to here
TODO Move content to here
public class InventoryActions {
@PersistenceContext private EntityManager em;
@Inject private Event<ExceptionToCatchEvent> catchEvent; (1)
public Integer queryForItem(Item item) {
try {
Query q = em.createQuery("SELECT i from Item i where i.id = :id");
q.setParameter("id", item.getId());
return q.getSingleResult();
} catch (PersistenceException e) {
catchEvent.fire(new ExceptionToCatchEvent(e)); (2)
}
}
}| 1 | The Event of generic type ExceptionToCatchEvent is injected into your class for use later within a try/catch block. |
| 2 | The event is fired with a new instance of ExceptionToCatchEvent constructed with the exception to be handled. |
| Exceptions are handled asynchronously. |
@ExceptionHandler (1)
public class MyHandlers {
void printExceptions(@Handles ExceptionEvent<Throwable> evt) { (2)
System.out.println("Something bad happened:" +
evt.getException().getMessage());
evt.handleAndContinue(); (3)
}
}| 1 | Exception handler methods are registered on beans annotated with @ExceptionHandler |
| 2 | The @Handles annotation on the first parameter designates this method as an exception handler. |
| 3 | This handler does not modify the invocation of subsequent handlers, as designated by invoking handleAndContinue(). |
| The current ProjectStage can be injected. |
@Inject
private ProjectStage projectStage;
//...
boolean isDevProjectStage = ProjectStage.Development.equals(this.projectStage);| You can also use the ProjectStage at XHTML files. |
<h:panelGroup layout="block"rendered="#{applicationConfig.projectStage == 'Development'}" >
<!-- HTML Snippet is shown only in Development stage -->
</h:panelGroup>| Besides custom ProjectStages it is possible to use the following pre-defined ProjectStages: |
| It can be set using DeltaSpike Configuration |
-D org.apache.deltaspike.ProjectStage=DevelopmentString userName = ConfigResolver.getPropertyValue("user.name"); (1)
String dbUserName = ConfigResolver.getPropertyAwarePropertyValue("db.username"); (2)
Integer dbPort = ConfigResolver
.resolve("db.port") (3)
.as(Integer.class)
.withProjectStage(true)
.withDefault(3306)
.getValue();
Date deadline = ConfigResolver.resolve("project.deadline") (4)
.as(Date.class, new CustomDateConverter()).getValue());user.name = "Rafael" (1)
db.username.Production = "Antoine" (2)
db.username.Development = "Benevides" (2)
db.port = 1234 (3)
project.deadline = 2017-04-01 (4)@ApplicationScoped
public class SomeRandomService
{
@Inject
@ConfigProperty(name = "endpoint.poll.interval")
private Integer pollInterval;
@Inject
@ConfigProperty(name = "endpoint.poll.servername")
private String pollUrl;
...
}How to provide these Properties to DeltaSpike?
| By default there are implementations for the following configuration sources (listed in the lookup order): |
| You can also specify your own config file or create a custom ConfigSource (example: read from XML, JSON, DB, etc) |
| DeltaSpike has simple APIs for performing basic resource loading and property file reading. |
@Inject
@InjectableResource("myfile.properties")
private InputStream is;
public String getVersion() throws IOException {
try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
return br.readLine();
}
}| The InjectableResourceProvider interface can be implemented to allow reading from alternate sources if needed (e.g. database LOBs, NoSQL storage areas). |